package com.gurun.camera.device.util;

import android.app.Activity;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.danale.cloud.activity.OrderDetailWebViewActivity;
import com.danale.sdk.Danale;
import com.danale.sdk.platform.cache.UserCache;
import com.danale.sdk.platform.constant.cloud.CloudState;
import com.danale.sdk.platform.constant.cloud.ServiceType;
import com.danale.sdk.platform.constant.cloud.UseType;
import com.danale.sdk.platform.constant.device.ProductType;
import com.danale.sdk.platform.entity.cloud.CloudStateInfo;
import com.danale.sdk.platform.entity.cloud.DeviceChannel;
import com.danale.sdk.platform.entity.cloud.UserCloudInfo;
import com.danale.sdk.platform.entity.device.Device;
import com.danale.sdk.platform.result.cloud.GetCloudStateResult;
import com.danale.sdk.platform.result.cloud.GetUserCloudInfoResult;
import com.danale.sdk.utils.LogUtil;
import com.gurun.camera.R;
import com.gurun.camera.device.cache.DeviceCloudCache;
import com.gurun.camera.device.constant.AchieveType;
import com.gurun.camera.model.CloudDetailState;
import com.gurun.camera.model.DeviceCloudInfo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.keyboardsurfer.android.widget.crouton.Crouton;
import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func3;
import rx.functions.FuncN;

public class CloudHelper {
    private static final String TAG = CloudHelper.class.getSimpleName();

    public static Observable<DeviceCloudInfo> getCloudInfoByDevice(Device device, AchieveType type) {
        if (type == AchieveType.CACHE_ONLY) {
            return getCloudInfoFromCache(device);
        } else if (type == AchieveType.SERVER_ONLY) {
            return getCloudInfoFromServer(device);
        } else if (type == AchieveType.CACHE_FIRST) {
            return Observable.concat(getCloudInfoFromCache(device),
                    getCloudInfoFromServer(device))
                    .takeFirst(new Func1<DeviceCloudInfo, Boolean>() {
                        @Override
                        public Boolean call(DeviceCloudInfo deviceCloudInfo) {
                            return deviceCloudInfo != null;
                        }
                    });
        } else if (type == AchieveType.SERVER_FIRST) {
            return Observable.concat(getCloudInfoFromServer(device),
                    getCloudInfoFromCache(device))
                    .takeFirst(new Func1<DeviceCloudInfo, Boolean>() {
                        @Override
                        public Boolean call(DeviceCloudInfo deviceCloudInfo) {
                            return deviceCloudInfo != null;
                        }
                    });
        } else if (type == AchieveType.DEFAULT) {
            return Observable.concat(getCloudInfoFromCache(device),
                    getCloudInfoFromServer(device)
                    );
        }

        return Observable.error(new Exception("Not support achievetype"));
    }


    public static Observable<List<DeviceCloudInfo>> getCloudInoByDevList(final List<Device> devices, AchieveType type) {
        if (type == AchieveType.CACHE_ONLY) {
            return getCloudInfosFromCache(devices);
        } else if (type == AchieveType.SERVER_ONLY) {
            return getCloudInfosFromServer(devices);
        } else if (type == AchieveType.CACHE_FIRST) {
            return Observable.concat(getCloudInfosFromCache(devices),
                    getCloudInfosFromServer(devices))
                    .takeFirst(new Func1<List<DeviceCloudInfo>, Boolean>() {
                        @Override
                        public Boolean call(List<DeviceCloudInfo> deviceCloudInfo) {
                            return deviceCloudInfo != null && deviceCloudInfo.size() == devices.size();
                        }
                    });
        } else if (type == AchieveType.SERVER_FIRST) {
            return Observable.concat(getCloudInfosFromServer(devices),
                    getCloudInfosFromCache(devices))
                    .takeFirst(new Func1<List<DeviceCloudInfo>, Boolean>() {
                        @Override
                        public Boolean call(List<DeviceCloudInfo> deviceCloudInfo) {
                            return  deviceCloudInfo != null && deviceCloudInfo.size() == devices.size();
                        }
                    });
        } else if (type == AchieveType.DEFAULT) {
            return Observable.concat(getCloudInfosFromCache(devices),
                    getCloudInfosFromServer(devices));
        }

        return Observable.error(new Exception("Not support achievetype"));
    }



    private static List<Observable<List<DeviceCloudInfo>>> classifyGetCloudInfoByDevList(List<Device> deviceList){
        HashMap<ServiceType,List<Device>> map = new HashMap<>();
        List<Observable<List<DeviceCloudInfo>>> obserList = new ArrayList<>();
        if(deviceList != null){
            for(Device dev : deviceList){
                List<Device> devices = map.get(getServiceType(dev));
                if(devices == null){
                    devices = new ArrayList<>();
                    map.put(getServiceType(dev),devices);
                }
                devices.add(dev);
            }
        }

        for(ServiceType serviceType : map.keySet()){
            obserList.add(getCloudInfosFromServerByServiceType(map.get(serviceType),serviceType));
        }

       return obserList;
    }




    private static Observable<DeviceCloudInfo> getCloudInfoFromServer(Device device){
        return Observable.zip(Observable.just(device),
                        Danale.get().getCloudService().getUserCloudInfo(1, getServiceType(device), createDevChannels(Arrays.asList(device))),
                        Danale.get().getCloudService().getCloudState(1, createDevChannels(Arrays.asList(device))),
                        new Func3<Device, GetUserCloudInfoResult, GetCloudStateResult, DeviceCloudInfo>() {
                            @Override
                            public DeviceCloudInfo call(Device device, GetUserCloudInfoResult getUserCloudInfoResult, GetCloudStateResult getCloudStateResult) {
                                DeviceCloudInfo info = new DeviceCloudInfo();
                                UserCloudInfo userCloudInfo = getUserCloudInfoResult.getUserCloudInfoList().get(0);
                                info.setDevice(device);
                                info.setUsed(userCloudInfo.getUseType() == UseType.USED);

                                info.setCloudState(getCloudDetailState(getCloudStateResult.getCloudStates().get(0).getCloudState(),getUserCloudInfoResult.getUserCloudInfoList().get(0)));
                                info.setCloudInfo(userCloudInfo);
                                info.setDeviceId(device.getDeviceId());
                                LogUtil.d(TAG,"getCloudInfoFromServer : result coming");
                                return info;
                            }
                        }).doOnNext(new Action1<DeviceCloudInfo>() {
                    @Override
                    public void call(DeviceCloudInfo cloudInfo) {
                        LogUtil.d(TAG,"getCloudInfoFromServer : updateCache");
                        DeviceCloudCache.getInstance().updateCache(cloudInfo);
                    }
                });
    }

    private static Observable<List<DeviceCloudInfo>> getCloudInfosFromServer(List<Device> devices){
        return  Observable.zip(classifyGetCloudInfoByDevList(devices), new FuncN<List<DeviceCloudInfo>>() {

                @Override
                public List<DeviceCloudInfo> call(Object... args) {
                    List<DeviceCloudInfo> list = new ArrayList<DeviceCloudInfo>();
                    int length = args.length;
                    for(int i = 0; i < length ; i ++){
                        list.addAll((List<DeviceCloudInfo>) args[i]);
                    }
                    return list;
                }
            });

    }


    private static Observable<List<DeviceCloudInfo>> getCloudInfosFromServerByServiceType(List<Device> devices, ServiceType type){
        return Observable.zip(Observable.just(devices),
                Danale.get().getCloudService().getUserCloudInfo(1, type, createDevChannels(devices)),
                Danale.get().getCloudService().getCloudState(1, createDevChannels(devices)),
                new Func3<List<Device>, GetUserCloudInfoResult, GetCloudStateResult, List<DeviceCloudInfo>>() {
                    @Override
                    public List<DeviceCloudInfo> call(List<Device> devices, GetUserCloudInfoResult getUserCloudInfoResult, GetCloudStateResult getCloudStateResult) {
                        Map<String,DeviceCloudInfo> map = new HashMap<String, DeviceCloudInfo>();
                        if(devices != null){
                            for(Device dev : devices){
                                DeviceCloudInfo deviceCloudInfo = map.get(dev.getDeviceId());
                                if(deviceCloudInfo == null){
                                    deviceCloudInfo = new DeviceCloudInfo();
                                    deviceCloudInfo.setDevice(dev);
                                    deviceCloudInfo.setDeviceId(dev.getDeviceId());
                                }
                                map.put(dev.getDeviceId(),deviceCloudInfo);
                            }
                        }

                        if(getUserCloudInfoResult.getUserCloudInfoList() != null){
                            for(UserCloudInfo cloudInfo : getUserCloudInfoResult.getUserCloudInfoList()){
                                DeviceCloudInfo deviceCloudInfo = map.get(cloudInfo.getDeviceId());
                                if(deviceCloudInfo != null){
                                    deviceCloudInfo.setCloudInfo(cloudInfo);
                                }
                            }
                        }

                        if(getCloudStateResult.getCloudStates() != null){
                            for(CloudStateInfo stateInfo : getCloudStateResult.getCloudStates()){
                                DeviceCloudInfo deviceCloudInfo = map.get(stateInfo.getDeviceId());
                                if(deviceCloudInfo != null){
                                    deviceCloudInfo.setCloudState(getCloudDetailState(stateInfo.getCloudState(),deviceCloudInfo.getCloudInfo()));
                                }
                            }
                        }

                        LogUtil.d(TAG,"getCloudInfoFromServer : result coming");
                        return new ArrayList<DeviceCloudInfo>(map.values());
                    }
                }).doOnNext(new Action1<List<DeviceCloudInfo>>() {
            @Override
            public void call(List<DeviceCloudInfo> deviceCloudInfos) {
                DeviceCloudCache.getInstance().updateCache(deviceCloudInfos);
            }

        });
    }

    private static Observable<DeviceCloudInfo> getCloudInfoFromCache(Device device){
        return Observable.just(DeviceCloudCache.getInstance().getCloudInfoByDeviceId(device.getDeviceId()));
    }

    private static Observable<List<DeviceCloudInfo>> getCloudInfosFromCache(List<Device> devices){
         return Observable.just(devices)
                    .map(new Func1<List<Device>, List<String>>() {
                        @Override
                        public List<String> call(List<Device> devices) {
                            List<String> list = new ArrayList<String>();
                            if(devices != null){
                                for(Device dev : devices){
                                    list.add(dev.getDeviceId());
                                }
                            }
                            return list;
                        }
                    }).map(new Func1<List<String>, List<DeviceCloudInfo>>() {
                @Override
                public List<DeviceCloudInfo> call(List<String> devIds) {
                    return DeviceCloudCache.getInstance().getCloudInfosByDeviceIds(devIds);
                }
            });
    }

    private static ServiceType getServiceType(Device dev){
        if(dev == null){
        }
        if(dev.getProductTypes() != null){
            if(dev.getProductTypes().contains(ProductType.IPC)){
                return ServiceType.IPCAM;
            }else if(dev.getProductTypes().contains(ProductType.DVR) || dev.getProductTypes().contains(ProductType.NVR)){
                return ServiceType.DVR_NVR;
            }else if(dev.getProductTypes().contains(ProductType.DOORBELL)){
                return ServiceType.DOORBELL;
            }else if(dev.getProductTypes().contains(ProductType.VISUAL_GARAGE_DOOR)){
                return ServiceType.GARAGE_DOOR;
            }else {
                return ServiceType.ALL;
            }

        }else {
            return ServiceType.ALL;
        }
    }

    private static List<DeviceChannel> createDevChannels(List<Device> devList){
        List<DeviceChannel> list = new ArrayList<>();
        if(devList != null){
            for(Device dev : devList){
                //目前ipc,dvr,nvr的channel 都为1
                DeviceChannel channel = new DeviceChannel(dev.getDeviceId(),1);
                list.add(channel);
            }
        }

        return list;
    }

    /**
     * 对设备云服务排序
     * 1.未开通 > 已开通 > 不支持开通
     * 2.未使用云服务 > 已使用云服务
     * 3.按照过期时间排序,过期时间近的排前面
     * @param list
     */
    public static void sortDeviceCloudInfoList(List<DeviceCloudInfo> list){
        Collections.sort(list,new CloudComparator());
    }

    private static CloudDetailState getCloudDetailState(CloudState state, UserCloudInfo cloudInfo){
        if(state == CloudState.NOT_SUPPERT){
            return CloudDetailState.NOT_SUPPORT;
        }else if(state == CloudState.NOT_OPEN){
            if(cloudInfo.getUseType() == UseType.USED){
                return CloudDetailState.HAS_EXPIRED;
            }else {
                return CloudDetailState.NOT_OPEN;
            }
        }else {
            if(cloudInfo == null){
                return CloudDetailState.OPENED_NORMAL;
            }else{
                if(cloudInfo.getExpireTime() < System.currentTimeMillis()){
                    return CloudDetailState.HAS_EXPIRED;
                }else if(cloudInfo.getExpireTime() < System.currentTimeMillis() + 7 * 24 * 3600 * 1000 ){
                    return CloudDetailState.NEAR_EXPIRE;
                }else {
                    return CloudDetailState.OPENED_NORMAL;
                }
            }
        }
    }

    public static Crouton getAlertCrouton(final Activity activity, final DeviceCloudInfo info, final Device device, int viewGroup, boolean freeCloudAvailable){
        if(info.getCloudState() == CloudDetailState.NEAR_EXPIRE){
            return getNearExpireCloud(activity,info,device,viewGroup);
        }else if(info.getCloudState() == CloudDetailState.HAS_EXPIRED){
            return getHasExpiredCloud(activity,info,device,viewGroup);
        }else if(info.getCloudState() == CloudDetailState.NOT_OPEN){
            return getNotOpenCloud(activity,info,device,viewGroup,freeCloudAvailable);
        }else{
            return null;
        }
    }

    private static Crouton getNearExpireCloud(final Activity activity, final DeviceCloudInfo info, final Device device, int viewGroup){
            RelativeLayout layout = new RelativeLayout(activity);
            layout.setBackgroundResource(R.color.light_orange);
            layout.setPadding(20,20,20,20);

            TextView contentTv = new TextView(activity);
            contentTv.setText(activity.getString(R.string.near_expire,(info.getCloudInfo().getExpireTime() - System.currentTimeMillis()) / (3600 * 24 * 1000)));
            contentTv.setTextColor(activity.getResources().getColor(R.color.white));
            RelativeLayout.LayoutParams lp1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp1.addRule(RelativeLayout.CENTER_VERTICAL);
            contentTv.setLayoutParams(lp1);
            layout.addView(contentTv);

            ImageView gotoIv = new ImageView(activity);
//            gotoIv.setImageResource(R.drawable.return_white);
            gotoIv.setRotation(180f);
            gotoIv.setId(ViewIdGenerator.generateViewId());
            RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp2.addRule(RelativeLayout.CENTER_VERTICAL);
            lp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            gotoIv.setLayoutParams(lp2);
            layout.addView(gotoIv);

            TextView gotoTv = new TextView(activity);
            gotoTv.setText(activity.getString(R.string.renew));
            gotoTv.setTextColor(activity.getResources().getColor(R.color.white));
            RelativeLayout.LayoutParams lp3 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp3.addRule(RelativeLayout.CENTER_VERTICAL);
            lp3.addRule(RelativeLayout.LEFT_OF,gotoIv.getId());
            gotoTv.setLayoutParams(lp3);
            layout.addView(gotoTv);

            final Crouton notifyCloudView = Crouton.make(activity, layout, viewGroup);
            notifyCloudView.setConfiguration(new de.keyboardsurfer.android.widget.crouton.Configuration.Builder().setDuration(8000).build());
            layout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    OrderDetailWebViewActivity.startActivityForUpdateService(activity,info.getCloudInfo(),device.getAlias(), ClassCodeUtil.convertClassCode(device.getDeviceType()), false, 0);
                    notifyCloudView.hide();
                }
            });
            return notifyCloudView;
    }

    private static Crouton getHasExpiredCloud(final Activity activity, final DeviceCloudInfo info, final Device device, int viewGroup){
            RelativeLayout layout = new RelativeLayout(activity);
            layout.setBackgroundResource(R.color.light_orange);
            layout.setPadding(20,20,20,20);

            TextView contentTv = new TextView(activity);
            contentTv.setText(R.string.dev_cloud_has_expired);
            contentTv.setTextColor(activity.getResources().getColor(R.color.white));
            RelativeLayout.LayoutParams lp1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp1.addRule(RelativeLayout.CENTER_VERTICAL);
            contentTv.setLayoutParams(lp1);
            layout.addView(contentTv);

            ImageView gotoIv = new ImageView(activity);
//            gotoIv.setImageResource(R.drawable.return_white);
            gotoIv.setRotation(180f);
            gotoIv.setId(ViewIdGenerator.generateViewId());
            RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp2.addRule(RelativeLayout.CENTER_VERTICAL);
            lp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            gotoIv.setLayoutParams(lp2);
            layout.addView(gotoIv);

            TextView gotoTv = new TextView(activity);
            gotoTv.setText(activity.getString(R.string.renew));
            gotoTv.setTextColor(activity.getResources().getColor(R.color.white));
            RelativeLayout.LayoutParams lp3 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            lp3.addRule(RelativeLayout.CENTER_VERTICAL);
            lp3.addRule(RelativeLayout.LEFT_OF,gotoIv.getId());
            gotoTv.setLayoutParams(lp3);
            layout.addView(gotoTv);

            final Crouton notifyCloudView = Crouton.make(activity, layout, viewGroup);
            notifyCloudView.setConfiguration(new de.keyboardsurfer.android.widget.crouton.Configuration.Builder().setDuration(8000).build());
            layout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    OrderDetailWebViewActivity.startActivityForUpdateService(activity,info.getCloudInfo(),device.getAlias(), ClassCodeUtil.convertClassCode(device.getDeviceType()), false, 0);
                    notifyCloudView.hide();
                }
            });
            return notifyCloudView;
    }

    private static Crouton getNotOpenCloud(final Activity activity, final DeviceCloudInfo info, final Device device, int viewGroup, boolean freeCloudAvailable){
        RelativeLayout layout = new RelativeLayout(activity);
        layout.setBackgroundResource(R.color.light_orange);
        layout.setPadding(10,20,5,20);

        TextView contentTv = new TextView(activity);
        contentTv.setText(R.string.dev_not_yet_open_cloud);
        contentTv.setTextColor(activity.getResources().getColor(R.color.white));
        RelativeLayout.LayoutParams lp1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        lp1.addRule(RelativeLayout.CENTER_VERTICAL);
        contentTv.setLayoutParams(lp1);
        layout.addView(contentTv);

        ImageView gotoIv = new ImageView(activity);
//        gotoIv.setImageResource(R.drawable.return_white);
        gotoIv.setRotation(180f);
        gotoIv.setId(ViewIdGenerator.generateViewId());
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        lp2.addRule(RelativeLayout.CENTER_VERTICAL);
        lp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        gotoIv.setLayoutParams(lp2);
        layout.addView(gotoIv);

        TextView gotoTv = new TextView(activity);
        if (UserCache.getCache().isAutoPay()) {
            if (freeCloudAvailable) {
                gotoTv.setText(activity.getString(R.string.free_trial_30_days));
            } else {
                gotoTv.setText(activity.getString(R.string.subscribe));
            }
        } else {
            gotoTv.setText(activity.getString(R.string.purchase));
        }
        gotoTv.setTextColor(activity.getResources().getColor(R.color.white));
        RelativeLayout.LayoutParams lp3 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        lp3.addRule(RelativeLayout.CENTER_VERTICAL);
        lp3.addRule(RelativeLayout.LEFT_OF,gotoIv.getId());
        gotoTv.setLayoutParams(lp3);
        layout.addView(gotoTv);

        final Crouton notifyCloudView = Crouton.make(activity, layout, viewGroup);
        notifyCloudView.setConfiguration(new de.keyboardsurfer.android.widget.crouton.Configuration.Builder().setDuration(8000).build());
        layout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                OrderDetailWebViewActivity.startActivityForAddService(activity,info.getDevice().getDeviceId(), ServiceTypeUtil.getServiceType(info.getDevice()),
                        info.getDevice().getAlias(), ClassCodeUtil.convertClassCode(info.getDevice().getDeviceType()), false, 0);
                notifyCloudView.hide();
            }
        });
        return notifyCloudView;
    }
}
